// DMPluginWrapper.h

#pragma once

#include "dmalgointerfaces.h"


using namespace System;

#include "DMEnumerationWrappers.h"
#include "DMMiningParameter.h"

namespace Microsoft
{
namespace SqlServer
{
namespace DataMining
{
namespace PluginAlgorithms
{
    ref class AttributeSet;    
	ref class AlgorithmBase;
	ref class ModelServices;

	// Contains information about one parameter of a custom function
	ref class CustomFunctionParameterInfo
	{
	internal:
		CustomFunctionParameterInfo()
		{
			m_paramType = DMFPT_UNKNOWN;
			m_varType	= VT_NULL;
			m_fIsRequired = false;
			m_nParamIndex = -1;
			m_ManagedType	=	nullptr;
		}

		DM_FUNC_PARAM_TYPE		m_paramType;
		VARTYPE					m_varType;
		bool					m_fIsRequired;
		int						m_nParamIndex;
		Type^					m_ManagedType;

		property DM_FUNC_PARAM_TYPE	ParamType
		{
			DM_FUNC_PARAM_TYPE	get()
			{
				return m_paramType;
			}
			void set(DM_FUNC_PARAM_TYPE	 val)
			{
				m_paramType = val;
			}
		}

		property VARTYPE			DataType
		{
			VARTYPE get()
			{
				return m_varType;
			}
			void set(VARTYPE val)
			{
				m_varType = val;
			}
		}

		property bool	IsRequired
		{
			bool get()
			{
				return m_fIsRequired;
			}
			void set(bool val)
			{
				m_fIsRequired = val;
			}
		}

		property int ParamIndex
		{
			int get()
			{
				return m_nParamIndex;
			}
			void set(int val)
			{
				m_nParamIndex = val;
			}
		}


		property Type^ ManagedType
		{
			Type^ get()
			{
				return m_ManagedType;
			}
			void set( Type^ val)
			{
				m_ManagedType = val;
			}
		}
	};

	ref class CustomFunctionFlagInfo
	{
	internal:
		CustomFunctionFlagInfo()
		{
			m_strFlagName = nullptr;
			m_nParamIndex = -1;
		}
		String^					m_strFlagName;
		int						m_nParamIndex;

		property String^ Name
		{
			String^ get()
			{
				return m_strFlagName;
			}
			void set(String^ val)
			{
				m_strFlagName = val;
			}
		}

		property int ParamIndex
		{
			int get()
			{
				return m_nParamIndex;
			}
			void set(int val)
			{
				m_nParamIndex = val;
			}
		}
	};
	
	// Contains information about the custom functions exposed by the 
	// plug-in algorithm. 
	ref class CustomFunctionInfo
	{

	internal:
		CustomFunctionInfo(MethodInfo^ mi)
		{
			m_fValid			= false;
			m_strErrorMessage	= gcnew String("Function info was not initialized");
			m_methodInfo		= mi;
			m_strSignature		= String::Empty;
			m_fReturnsTable		= false;
			m_strDescription	= String::Empty;
			m_strHelpFile		= String::Empty;
			m_HelpContext		= -1;
			m_rgParameters		= nullptr;
			m_rgFlags			= nullptr;
			m_ReturnType		= nullptr;

			m_rgUsageTypes		=	gcnew array<int>(0);
			m_rgParameters		=	gcnew array<CustomFunctionParameterInfo^>(0);
			m_rgFlags			=	gcnew array<CustomFunctionFlagInfo^>(0);
		}

		bool									m_fValid;
		String^									m_strErrorMessage;
		MethodInfo^								m_methodInfo;
		String^									m_strSignature;
		bool									m_fReturnsTable;
		String^									m_strDescription;
		String^									m_strHelpFile;
		LONG									m_HelpContext;
		array<CustomFunctionParameterInfo^>^	m_rgParameters;
		array<CustomFunctionFlagInfo^>^			m_rgFlags;
		Type^									m_ReturnType;
		CustomFunctionParameterInfo^			m_CurrentCase;
		array<int>^								m_rgUsageTypes;


		void		SetInvalid( String^ reason )
		{
			m_fValid = false;
			m_strErrorMessage = reason;
		}

		void		SetValid()
		{
			m_fValid = true;
			m_strErrorMessage = String::Empty;
		}

		/*int			GetUsageType( int nIndex )
		{
			return m_rgUsageTypes[nIndex];
		}*/


		void AddParameter(CustomFunctionParameterInfo^ param)
		{

			Array::Resize( m_rgParameters, m_rgParameters->Length + 1);
			m_rgParameters[m_rgParameters->Length-1]	= param;
			int		nParamIndex	=	m_rgParameters->Length-1;

			int	nOld = m_rgUsageTypes->Length;
			Array::Resize( m_rgUsageTypes, nOld + 1);
			m_rgUsageTypes[nOld]	= 1 + nParamIndex;

		}

		void AddFlag(CustomFunctionFlagInfo^ flag)
		{
			Array::Resize( m_rgFlags, m_rgFlags->Length + 1);
			m_rgFlags[m_rgFlags->Length-1]	= flag;
			int		nFlagIndex	=	m_rgParameters->Length-1;

			int	nOld = m_rgUsageTypes->Length;
			Array::Resize( m_rgUsageTypes, nOld + 1);
			m_rgUsageTypes[nOld]	= -(1 + nFlagIndex);

		}

		property MethodInfo^	Info
		{
			MethodInfo^ get()
			{
				return m_methodInfo;
			}
		}


		property String ^    Name
		{
			String ^    get()
			{
				return m_methodInfo->Name;
		    }
		}

		property String^	Error
		{
			String^ get()
			{
				return m_strErrorMessage;
			}
		}

		property String ^    Signature
		{
			String ^    get()
			{
				return m_strSignature;
		    }
			void set(String^ val)
			{
				m_strSignature = val;
			}
		}

		property bool		ReturnsTable
		{
			bool		get()
			{
				return m_fReturnsTable;
			}
		}

		property Type^ ReturnType
		{
			Type^		get()
			{
				return m_ReturnType;
			}
			void set(Type^ retType)
			{
				m_ReturnType = retType;
				if( retType == System::Data::DataTable::typeid  )
				{
					m_fReturnsTable = true;
				}
			}
		}

	
		property String^ Description
		{
			String^	get()
			{
				return m_strDescription;
			}
			void set(String^ val)
			{
				if(val != nullptr )
					m_strDescription = val;
			}
		}

		property String^ HelpFile
		{
			String^	get()
			{
				return m_strHelpFile;
			}
			void set(String^ val)
			{
				if( val != nullptr )
				{
					m_strHelpFile = val;
				}
			}
		}

		property int HelpContext
		{
			int get()
			{
				return m_HelpContext;
			}
			void set(int val)
			{
				m_HelpContext = val;
			}

		}

		property int ParametersCount
		{
			int get()
			{
				if( m_rgParameters == nullptr )
					return 0;
				else
					return m_rgParameters->Length;
			}
		}

		property int FlagsCount
		{
			int get()
			{
				if( m_rgFlags == nullptr )
					return 0;
				else
					return m_rgFlags->Length;
			}
		}

		property CustomFunctionParameterInfo^	Parameter[int]
		{
			CustomFunctionParameterInfo^ get(int i)
			{
				return m_rgParameters[i];
			}
		}

		property CustomFunctionFlagInfo^	Flag[int]
		{
			CustomFunctionFlagInfo^ get(int i)
			{
				return m_rgFlags[i];
			}
		}	

		property bool Valid
		{
			bool get()
			{
				return m_fValid;
			}
		}


		property CustomFunctionParameterInfo^	CurrentCase
		{
			CustomFunctionParameterInfo^ get()
			{
				return m_CurrentCase;
			}

			void set(CustomFunctionParameterInfo^ param)
			{
				int	nOld = m_rgUsageTypes->Length;
				Array::Resize( m_rgUsageTypes, nOld + 1);
				m_rgUsageTypes[nOld]	= 0;
				m_CurrentCase = param;
			}
		}


	};

	///////////////////////////////////////////////////////////
	// InternalTableResult-- Implements IDMTableResult
	private ref class InternalTableResult : 
                            public ICLR_DMTableResult
	{
	internal:
		InternalTableResult( System::Data::DataTable^	table)
		{
			m_table = table;
			m_nRowIndex = 0;
			m_nMax	=	table->Rows->Count;
		}
	protected:
		System::Data::DataTable^ m_table;
		int						m_nRowIndex;
		int						m_nMax;

	public:
		virtual HRESULT ExportedGetColumnCount(
				ULONG*			out_pulColumnInfo)sealed;
		
		virtual HRESULT ExportedStart()sealed;

		virtual HRESULT ExportedMoveToNextRow()sealed;

		virtual HRESULT ExportedGetColumnValue(
				IDMContextServices*			in_pContext,
				ULONG						in_iColumn,
				DMVariantPtr				io_pColumnValue)sealed;
	};

}
}
}
}
